﻿using System;

public class Mapper004 : MapperDefault
{
    internal int chrAddressSelect;
    public const int CMD_SEL_1K_VROM_1000 = 2;
    public const int CMD_SEL_1K_VROM_1400 = 3;
    public const int CMD_SEL_1K_VROM_1800 = 4;
    public const int CMD_SEL_1K_VROM_1C00 = 5;
    public const int CMD_SEL_2_1K_VROM_0000 = 0;
    public const int CMD_SEL_2_1K_VROM_0800 = 1;
    public const int CMD_SEL_ROM_PAGE1 = 6;
    public const int CMD_SEL_ROM_PAGE2 = 7;
    internal int command;
    internal int irqCounter;
    internal int irqEnable;
    internal int irqLatchValue;
    internal int pageNumber;
    internal bool prgAddressChanged;
    internal int prgAddressSelect;

    public override void clockIrqCounter()
    {
        if (this.irqEnable == 1)
        {
            this.irqCounter--;
            if (this.irqCounter < 0)
            {
                base.nes.Cpu.requestIrq(0);
                this.irqCounter = this.irqLatchValue;
            }
        }
    }

    public virtual void executeCommand(int cmd, int arg)
    {
        if (cmd == 0)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0);
                this.load1kVromBank(arg + 1, 0x400);
            }
            else
            {
                this.load1kVromBank(arg, 0x1000);
                this.load1kVromBank(arg + 1, 0x1400);
            }
        }
        else if (cmd == 1)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0x800);
                this.load1kVromBank(arg + 1, 0xc00);
            }
            else
            {
                this.load1kVromBank(arg, 0x1800);
                this.load1kVromBank(arg + 1, 0x1c00);
            }
        }
        else if (cmd == 2)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0x1000);
            }
            else
            {
                this.load1kVromBank(arg, 0);
            }
        }
        else if (cmd == 3)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0x1400);
            }
            else
            {
                this.load1kVromBank(arg, 0x400);
            }
        }
        else if (cmd == 4)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0x1800);
            }
            else
            {
                this.load1kVromBank(arg, 0x800);
            }
        }
        else if (cmd == 5)
        {
            if (this.chrAddressSelect == 0)
            {
                this.load1kVromBank(arg, 0x1c00);
            }
            else
            {
                this.load1kVromBank(arg, 0xc00);
            }
        }
        else if (cmd == 6)
        {
            if (this.prgAddressChanged)
            {
                if (this.prgAddressSelect == 0)
                {
                    this.load8kRomBank((base.nes.Rom.RomBankCount - 1) * 2, 0xc000);
                }
                else
                {
                    this.load8kRomBank((base.nes.Rom.RomBankCount - 1) * 2, 0x8000);
                }
                this.prgAddressChanged = false;
            }
            if (this.prgAddressSelect == 0)
            {
                this.load8kRomBank(arg, 0x8000);
            }
            else
            {
                this.load8kRomBank(arg, 0xc000);
            }
        }
        else if (cmd == 7)
        {
            this.load8kRomBank(arg, 0xa000);
            if (this.prgAddressChanged)
            {
                if (this.prgAddressSelect == 0)
                {
                    this.load8kRomBank((base.nes.Rom.RomBankCount - 1) * 2, 0xc000);
                }
                else
                {
                    this.load8kRomBank((base.nes.Rom.RomBankCount - 1) * 2, 0x8000);
                }
                this.prgAddressChanged = false;
            }
        }
    }

    public override void init(NES nes)
    {
        base.init(nes);
    }

    public override void loadROM(ROM rom)
    {
        if (rom.Valid)
        {
            this.load8kRomBank((base.nes.Rom.RomBankCount - 1) * 2, 0xc000);
            this.load8kRomBank(((base.nes.Rom.RomBankCount - 1) * 2) + 1, 0xe000);
            this.load8kRomBank(0, 0x8000);
            this.load8kRomBank(1, 0xa000);
            this.loadCHRROM();
            this.loadBatteryRam();
            base.nes.Cpu.requestIrq(2);
        }
    }

    public override void mapperInternalStateLoad(ByteBuffer buf)
    {
        base.mapperInternalStateLoad(buf);
        if (buf.readByte() == 1)
        {
            this.command = buf.readInt();
            this.prgAddressSelect = buf.readInt();
            this.chrAddressSelect = buf.readInt();
            this.pageNumber = buf.readInt();
            this.irqCounter = buf.readInt();
            this.irqLatchValue = buf.readInt();
            this.irqEnable = buf.readInt();
            this.prgAddressChanged = buf.readBoolean();
        }
    }

    public override void mapperInternalStateSave(ByteBuffer buf)
    {
        base.mapperInternalStateSave(buf);
        buf.putByte(1);
        buf.putInt(this.command);
        buf.putInt(this.prgAddressSelect);
        buf.putInt(this.chrAddressSelect);
        buf.putInt(this.pageNumber);
        buf.putInt(this.irqCounter);
        buf.putInt(this.irqLatchValue);
        buf.putInt(this.irqEnable);
        buf.putBoolean(this.prgAddressChanged);
    }

    public override void reset()
    {
        this.command = 0;
        this.prgAddressSelect = 0;
        this.chrAddressSelect = 0;
        this.pageNumber = 0;
        this.irqCounter = 0;
        this.irqLatchValue = 0;
        this.irqEnable = 0;
        this.prgAddressChanged = false;
    }

    public override void write(int address, short value_Renamed)
    {
        if (address < 0x8000)
        {
            base.write(address, value_Renamed);
        }
        else if (address == 0x8000)
        {
            this.command = value_Renamed & 7;
            int num = (value_Renamed >> 6) & 1;
            if (num != this.prgAddressSelect)
            {
                this.prgAddressChanged = true;
            }
            this.prgAddressSelect = num;
            this.chrAddressSelect = (value_Renamed >> 7) & 1;
        }
        else if (address == 0x8001)
        {
            this.executeCommand(this.command, value_Renamed);
        }
        else if (address == 0xa000)
        {
            if ((value_Renamed & 1) != 0)
            {
                base.nes.Ppu.Mirroring = 1;
            }
            else
            {
                base.nes.Ppu.Mirroring = 0;
            }
        }
        else if (address == 0xa001)
        {
            base.nes.Rom.SaveState = (value_Renamed & 1) != 0;
        }
        else if (address == 0xc000)
        {
            this.irqCounter = value_Renamed;
        }
        else if (address == 0xc001)
        {
            this.irqLatchValue = value_Renamed;
        }
        else if (address == 0xe000)
        {
            this.irqEnable = 0;
        }
        else if (address == 0xe001)
        {
            this.irqEnable = 1;
        }
    }
}

